package org.example.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.micrometer.common.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * @author 尹承
 */
public class HttpUtils {
    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
    private static final Random random = new Random();

    final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }	//将所有验证的结果都设为true
    };

    static {
        trustAllHosts();
    }

    @SuppressWarnings("rawtypes")
	public static HttpResult get(String url, Map<String,String> reqHeader, Map<String,Object> params,Class returnClass,Proxy proxy){
        if(reqHeader == null){
            reqHeader = new HashMap<>();
        }
        if(params == null){
            params = new HashMap<>();
        }
        if(reqHeader.get("Content-Type") == null || "".equals(reqHeader.get("Content-Type"))){
            reqHeader.put("Content-Type","application/x-www-form-urlencoded");
        }
        return doHttp(url,"GET",reqHeader,params,returnClass,0,0,proxy);
    }

    @SuppressWarnings("rawtypes")
	public static HttpResult get(String url, Map<String,String> reqHeader, Map<String,Object> params,Class returnClass,int readTimeoutMs,int connectTimeoutMs,Proxy proxy){
        if(reqHeader == null){
            reqHeader = new HashMap<>();
        }
        if(params == null){
            params = new HashMap<>();
        }
        if(reqHeader.get("Content-Type") == null || "".equals(reqHeader.get("Content-Type"))){
            reqHeader.put("Content-Type","application/x-www-form-urlencoded");
        }
        return doHttp(url,"GET",reqHeader,params,returnClass,readTimeoutMs,connectTimeoutMs,proxy);
    }

    @SuppressWarnings("rawtypes")
	public static HttpResult postApplicationJson(String url, Map<String,String> reqHeader, Object params,Class returnClass, Proxy proxy){
        if(reqHeader == null){
            reqHeader = new HashMap<>();
        }
        if(params == null){
            params = new HashMap<>();
        }
        if(reqHeader.get("Content-Type") == null || "".equals(reqHeader.get("Content-Type"))){
            reqHeader.put("Content-Type","application/json");
        }
        return doHttp(url,"POST",reqHeader,params,returnClass,0,0,proxy);
    }

    @SuppressWarnings("rawtypes")
	public static HttpResult postApplicationJson(String url, Map<String,String> reqHeader, Object params,Class returnClass,int readTimeoutMs,int connectTimeoutMs,Proxy proxy){
        if(reqHeader == null){
            reqHeader = new HashMap<>();
        }
        if(params == null){
            params = new Object();
        }
        if(reqHeader.get("Content-Type") == null || "".equals(reqHeader.get("Content-Type"))){
            reqHeader.put("Content-Type","application/json");
        }
        return doHttp(url,"POST",reqHeader,params,returnClass,readTimeoutMs,connectTimeoutMs,proxy);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
	public static HttpResult doHttp(String url,String Methods, Map<String,String> reqHeader, Object params,Class returnClass,int readTimeoutMs,int connectTimeoutMs, Proxy proxy){
        HttpResult httpResult = new HttpResult();
        HttpsURLConnection conns = null;
        HttpURLConnection conn = null;
        BufferedReader reader = null;
        PrintWriter writer = null;
        String content;
        StringBuilder sbf = new StringBuilder();
        String ContentType = reqHeader.get("Content-Type");
        String reqNo = String.valueOf(random.nextInt(1000));
        try{
            URL u = new URL(url);
            if (u.getProtocol().toLowerCase().equals("https")) {
                //trustAllHosts();
                if(proxy != null){
                    conns = (HttpsURLConnection)u.openConnection(proxy);
                }else {
                    conns = (HttpsURLConnection)u.openConnection();
                }
                conns.setHostnameVerifier(DO_NOT_VERIFY);
                conn = conns;
            } else {	//判断是https请求还是http请求
                if(proxy != null){
                    conn = (HttpURLConnection) u.openConnection(proxy);
                }else {
                    conn = (HttpURLConnection) u.openConnection();
                }
            }
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            //POST GET
            conn.setRequestMethod(Methods);
            if(ContentType !=null && !"".equals(ContentType)){
                conn.setRequestProperty("Content-Type",ContentType);
            }
            conn.setReadTimeout(readTimeoutMs);
            conn.setConnectTimeout(connectTimeoutMs);
            if(readTimeoutMs < 1000){
                conn.setReadTimeout(120000);
            }
            if(connectTimeoutMs < 1000){
                conn.setConnectTimeout(120000);
            }
            conn.setRequestProperty("accept","*/*");
            conn.setRequestProperty("connection","Keep-Alive");
            Set<Map.Entry<String, String>> entries = reqHeader.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                conn.setRequestProperty(entry.getKey(),entry.getValue());
            }
            log.info(reqNo+"请求url："+url);
            log.info(reqNo+"请求头："+reqHeader);
            //三种方式 get post post(application/json)
            if("application/json".equals(ContentType)){
                writer = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8));
                String jparams = "";
                if(params instanceof String){
                    jparams = (String)params;
                }else{
                    jparams = objectToJson(params);
                }
                log.info(reqNo+"请求参数："+jparams);
                writer.print(jparams);
                writer.flush();
            }else {
                StringBuilder sb = new StringBuilder();
                if(params instanceof  String && StringUtils.isNotEmpty((String)params)){
                    //参数类似  aaa=a1&bbb=b2
                    sb.append(params);
                }
                if(params instanceof Map params1){
                    Set<Map.Entry<String, Object>> entriesp = params1.entrySet();
                    for (Map.Entry<String, Object> entry : entriesp) {
                        Object value = entry.getValue();
                        String v = null;
                        if(value instanceof String){
                            v = value.toString();
                        }else{
                            v = objectToJson(value);
                        }
                        sb.append("&").append(entry.getKey()).append("=").append(URLEncoder.encode(v, StandardCharsets.UTF_8));
                    }
                }
                log.info(reqNo+"请求参数："+sb.toString());
                if(StringUtils.isNotEmpty(sb.toString())){
                    writer = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8));
                    writer.print(sb.toString());
                    writer.flush();
                }
            }
            //获取返回状态码
            InputStream inputStream = null;
            int statusCode = conn.getResponseCode();
            Map<String, List<String>> responesHeader =  conn.getHeaderFields();
            if (HttpURLConnection.HTTP_OK == conn.getResponseCode()) {
               inputStream = conn.getInputStream();
            } else {
               inputStream = conn.getErrorStream();
            }
            if(inputStream != null) {
            	reader = new BufferedReader(new InputStreamReader(inputStream));
                while((content = reader.readLine())!=null){
                    sbf.append(content);
                }
            }
            Object result = null;
            //获取返回信息
            if(String.class.equals(returnClass)){
                result = sbf.toString();
            }else if(returnClass == null){
            }else{
                if(StringUtils.isEmpty(sbf.toString())){
                }else if(statusCode == 200){
                    result = jsonToObject(sbf.toString(), returnClass);
                }
            }
            httpResult = new HttpResult(statusCode, responesHeader, result);
            log.info(reqNo+"响应状态码："+statusCode);
            log.info(reqNo+"响应头："+responesHeader);
            log.info(reqNo+"返回结果："+sbf.toString());
        }catch(Exception e){
        	log.error(reqNo+":"+e.getMessage(),e);
        }finally{
            if(writer!=null){
                writer.close();
            }
            if(reader!=null){
                try {
                    reader.close();
                } catch (IOException e) {
                	log.error(e.getMessage(),e);
                }
            }
            if(conn != null){
                conn.disconnect();
            }
        }
        return httpResult;
    }
    private static final ObjectMapper om = new ObjectMapper();

    public static String objectToJson(Object o) {
        String result = "{}";
        try (StringWriter sw = new StringWriter()){
            om.writeValue(sw, o);
            result = sw.toString();
        } catch (Exception e) {
            log.error("json异常",e);
        }
        return result;
    }

    public static <T> T jsonToObject(String json,Class<T> clazz) {
        T readValue = null;
        try {
            readValue = om.readValue(json, clazz);
        } catch (Exception e) {
            log.error("json异常",e);
        }
        return readValue;
    }

    /**
     * 不检查任何证书
     */
    private static void trustAllHosts() {
        // 创建信任管理器
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {

            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[]{};
            }

            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }
        }};

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            log.error("https初始化错误",e);
        }
    }

}